#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>


#include "elf.h"

static char* gElfStr = NULL;
int** cur_ebp = 0;

#define A(v) ((void**)(v))
#define VA(v) ((unsigned int)(v))

typedef struct _i2str{
	int i;
	char* str;
	char* descriptor;
} I2STR;

I2STR eh_class[] = {
	{0, "ELFCLASSNONE","Invalid class"}, {1, "ELFCLASS32", "32-bit objects"}, {2, "ELFCLASS64","64-bit objects"},
};
I2STR eh_data[] = {
	{0, "Invalid data encoding", ""}, {1, "2's complement, little endian", ""}, {2, "2's complement, big endian", ""},
};
I2STR eh_abi[] = {
	{0, "UNIX System V ABI", ""}, {1, "HP-UX", ""}, {2, "NetBSD.", ""}, {3, "Linux.", ""}, {6, "Sun Solaris.", ""}, {7, "IBM AIX.", ""}, {8, "SGI Irix.", ""},
	{9, "FreeBSD.", ""}, {10, "Compaq TRU64 UNIX.", ""}, {11, "Novell Modesto.", ""}, {12, "OpenBSD.", ""}, {64, "ARM EABI", ""}, {97, "ARM", ""},
	{255, "Standalone (embedded) application", ""},
};
I2STR eh_e_type[] = {
	{0, "No file type", ""}, {1, "Relocatable file", ""}, {2, "Executable file", ""}, {3, "Shared object file", ""},
	{4, "Core file", ""}, {5, "Number of defined types", ""},
};
I2STR eh_e_mach[] = {
	{0, "No machine", ""},	{1, "AT&T WE 32100", ""},	{2, "SUN SPARC", ""},	{3, "Intel 80386", ""},	{4, "Motorola m68k family", ""},
	{5, "Motorola m88k family", ""},	{7, "Intel 80860", ""},	{8, "MIPS R3000 big-endian", ""},	{9, "IBM System/370", ""},	{10, "MIPS R3000 little-endian", ""},
	{15, "HPPA"},	{17, "Fujitsu VPP500"},	{18, "Sun's v8plus"},	{19, "Intel 80960"},	{20, "PowerPC"},	{21, "PowerPC 64-bit"},	{22, "IBM S390"},
	{36, "NEC V800 series"},	{37, "Fujitsu FR20"},	{38, "TRW RH-32"},	{39, "Motorola RCE"},	{40, "ARM"},	{41, "Digital Alpha"},	{42, "Hitachi SH"},
	{43, "SPARC v9 64-bit"},	{44, "Siemens Tricore"},	{45, "Argonaut RISC Core"},	{46, "Hitachi H8/300"},	{47, "Hitachi H8/300H"},	{48, "Hitachi H8S"},
	{49, "Hitachi H8/500"},	{50, "Intel Merced"},	{51, "Stanford MIPS-X"},	{52, "Motorola Coldfire"},	{53, "Motorola M68HC12"},
	{54, "Fujitsu MMA Multimedia Accelerator"},	{55, "Siemens PCP"},	{56, "Sony nCPU embeeded RISC"},	{57, "Denso NDR1 microprocessor"},
	{58, "Motorola Start*Core processor"},	{59, "Toyota ME16 processor"},	{60, "STMicroelectronic ST100 processor"},	{61, "Advanced Logic Corp. Tinyj emb.fam"},
	{62, "AMD x86-64 architecture"},	{63, "Sony DSP Processor"},	{66, "Siemens FX66 microcontroller"},	{67, "STMicroelectronics ST9+ 8/16 mc"},
	{68, "STmicroelectronics ST7 8 bit mc"},	{69, "Motorola MC68HC16 microcontroller"},	{70, "Motorola MC68HC11 microcontroller"},
	{71, "Motorola MC68HC08 microcontroller"},	{72, "Motorola MC68HC05 microcontroller"},	{73, "Silicon Graphics SVx"},	{74, "STMicroelectronics ST19 8 bit mc"},
	{75, "Digital VAX"},	{76, "Axis Communications 32-bit embedded processor"},	{77, "Infineon Technologies 32-bit embedded processor"},
	{78, "Element 14 64-bit DSP Processor"},	{79, "LSI Logic 16-bit DSP Processor"},	{80, "Donald Knuth's educational 64-bit processor"},
	{81, "Harvard University machine-independent object files"},	{82, "SiTera Prism"},	{83, "Atmel AVR 8-bit microcontroller"},	{84, "Fujitsu FR30"},
	{85, "Mitsubishi D10V"},	{86, "Mitsubishi D30V"},	{87, "NEC v850"},	{88, "Mitsubishi M32R"},	{89, "Matsushita MN10300"},	{90, "Matsushita MN10200"},
	{91, "picoJava"},	{92, "OpenRISC 32-bit embedded processor"},	{93, "ARC Cores Tangent-A5"},	{94, "Tensilica Xtensa Architecture"},
};
I2STR sh_type[] = {
	{0,  "-"},//Section header table entry unused
	{1,  "Program_data"}, {2,  "Symbol_table"}, {3,  "String_table"},
	{4,  "Relocation_entries"},// with addends
	{5,  "Symbol_hash_table"}, {6,  "Dynamic_linking_info"}, {7,  "Notes"},
	{8,  "bss"},//Program space with no data (bss)
	{9,  "Relocation_entries"},//, no addends
	{10, "Reserved"}, {11, "Dynamic_link_symbol_table"}, {14, "Array_of_constructors"}, {15, "Array_of_destructors"},
	{16, "Array_of_pre-constructors"}, {17, "Section_group"}, {18, "Extended_section_indeces"}, {19, "Number of defined types."},
	{0x60000000, "Start OS-specific."}, {0x6ffffff5, "Object attributes."}, {0x6ffffff6, "GNU-style hash table."},
	{0x6ffffff7, "Prelink library list"}, {0x6ffffff8, "Checksum for DSO content."}, {0x6ffffffa, "Sun-specific low bound."},
	{0x6ffffffa, ""}, {0x6ffffffb, ""}, {0x6ffffffc, ""}, {0x6ffffffd, "Version definition section."},
	{0x6ffffffe, "Version needs section."}, {0x6fffffff, "Version symbol table."}, {0x6fffffff, "Sun-specific high bound."},
	{0x6fffffff, "End OS-specific type"}, {0x70000000, "Start of processor-specific"}, {0x7fffffff, "End of processor-specific"},
	{0x80000000, "Start of application-specific"}, {0x8fffffff, "End of application-specific"},
};
I2STR sym_type[] = {
	{0 , "NOTYPE "},		/* Symbol type is unspecified */
	{1 , "OBJECT "},		/* Symbol is a data object */
	{2 , "FUNC   "},		/* Symbol is a code object */
	{3 , "SECTION"},		/* Symbol associated with a section */
	{4 , "FILE   "},		/* Symbol's name is file name */
	{5 , "COMMON "},		/* Symbol is a common data object */
	{6 , "TLS    "},		/* Symbol is thread-local data object*/
	{7 , "NUM    "},		/* Number of defined types.  */
	{10, "LOOS   "},	    /* Start of OS-specific - Symbol is indirect code object*/
	{12, "HIOS   "},		/* End of OS-specific */
	{13, "LOPROC "},		/* Start of processor-specific */
	{15, "HIPROC "},		/* End of processor-specific */
};
I2STR sym_bind[] = {
	{0,  "LOCAL "},/* Local symbol */
	{1,  "GLOBAL"},/* Global symbol */
	{2,  "WEAK  "},/* Weak symbol */
	{3,  "NUMBER"},/* Number of defined types.  */
	{10, "UNIQUE"},/* Unique symbol.  */
	{12, "HIOS  "},/* End of OS-specific */
	{13, "LOPROC"},/* Start of processor-specific */
	{15, "HIPROC"},/* End of processor-specific */
};
I2STR sym_visibility[] = {
	{0,  "DEFAULT  ", "Default symbol visibility rules"},
	{1,  "INTERNAL ", "Processor specific hidden class"},
	{2,  "HIDDEN   ", "Sym unavailable in other modules"},
	{3,  "PROTECTED", "Not preemptible, not exported"},
};

I2STR reloc_type_i386[] = {
	{0,   "R_386_NONE         ", "No reloc"},
	{1,   "R_386_32           ", "Direct 32 bit "},
	{2,   "R_386_PC32         ", "PC relative 32 bit"},
	{3,   "R_386_GOT32        ", "32 bit GOT entry"},
	{4,   "R_386_PLT32        ", "32 bit PLT address"},
	{5,   "R_386_COPY         ", "Copy symbol at runtime"},
	{6,   "R_386_GLOB_DAT     ", "Create GOT entry"},
	{7,   "R_386_JMP_SLOT     ", "Create PLT entry"},
	{8,   "R_386_RELATIVE     ", "Adjust by program base"},
	{9,   "R_386_GOTOFF       ", "32 bit offset to GOT"},
	{10,  "R_386_GOTPC        ", "32 bit PC relative offset to GOT"},
	{11,  "R_386_32PLT        ", ""},
	{14,  "R_386_TLS_TPOFF    ", "Offset in static TLS block"},
	{15,  "R_386_TLS_IE       ", "Address of GOT entry for static TLS block offset"},
	{16,  "R_386_TLS_GOTIE    ", "GOT entry for static TLS block offset"},
	{17,  "R_386_TLS_LE       ", "Offset relative to static TLS block"},
	{18,  "R_386_TLS_GD       ", "Direct 32 bit for GNU version of general dynamic thread local data"},
	{19,  "R_386_TLS_LDM      ", "Direct 32 bit for GNU version of local dynamic thread local data in LE code"},
	{20,  "R_386_16           ", ""},
	{21,  "R_386_PC16         ", ""},
	{22,  "R_386_8            ", ""},
	{23,  "R_386_PC8          ", ""},
	{24,  "R_386_TLS_GD_32    ", "Direct 32 bit for general dynamic thread local data"},
	{25,  "R_386_TLS_GD_PUSH  ", "Tag for pushl in GD TLS code"},
	{26,  "R_386_TLS_GD_CALL  ", "Relocation for call to __tls_get_addr()"},
	{27,  "R_386_TLS_GD_POP   ", "Tag for popl in GD TLS code"},
	{28,  "R_386_TLS_LDM_32   ", "Direct 32 bit for local dynamic thread local data in LE code"},
	{29,  "R_386_TLS_LDM_PUSH ", "Tag for pushl in LDM TLS code"},
	{30,  "R_386_TLS_LDM_CALL ", "Relocation for call to __tls_get_addr() in LDM code"},
	{31,  "R_386_TLS_LDM_POP  ", "Tag for popl in LDM TLS code"},
	{32,  "R_386_TLS_LDO_32	  ", "Offset relative to TLS block"},
	{33,  "R_386_TLS_IE_32    ", "GOT entry for negated static TLS block offset"},
	{34,  "R_386_TLS_LE_32    ", "Negated offset relative to static TLS block"},
	{35,  "R_386_TLS_DTPMOD32 ", "ID of module containing symbol"},
	{36,  "R_386_TLS_DTPOFF32 ", "Offset in TLS block"},
	{37,  "R_386_TLS_TPOFF32  ", "Negated offset in static TLS block 38?"},
	{39,  "R_386_TLS_GOTDESC  ", "GOT offset for TLS descriptor. "},
	{40,  "R_386_TLS_DESC_CALL", "Marker of call through TLS descriptor for relaxation. "},
	{41,  "R_386_TLS_DESC     ", "TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol. "},
	{42,  "R_386_IRELATIVE    ", "Adjust indirectly by program base Keep this the last entry. "},
	{43,  "R_386_NUM          ", ""},
};
I2STR p_type_info[] = {
	{         0, "NULL        ", "Program header table entry unused"},
	{         1, "LOAD        ", "Loadable program segment"},
	{         2, "DYNAMIC     ", "Dynamic linking information"},
	{         3, "INTERP      ", "Program interpreter"},
	{         4, "NOTE        ", "Auxiliary information"},
	{         5, "SHLIB       ", "Reserved"},
	{         6, "PHDR        ", "Entry for header table itself"},
	{         7, "TLS         ", "Thread-local storage segment"},
	{         8, "NUM         ", "Number of defined types"},
	{0x60000000, "LOOS        ", "Start of OS-specific"},
	{0x6474e550, "GNU_EH_FRAME", "GCC .eh_frame_hdr segment"},
	{0x6474e551, "GNU_STACK   ", "Indicates stack executability"},
	{0x6474e552, "GNU_RELRO   ", "Read-only after relocation"},
	{0x6ffffffa, "LOSUNW      ", ""},
	{0x6ffffffa, "SUNWBSS     ", "Sun Specific segment"},
	{0x6ffffffb, "SUNWSTACK   ", "Stack segment"},
	{0x6fffffff, "HISUNW      ", ""},
	{0x6fffffff, "HIOS        ", "End of OS-specific"},
	{0x70000000, "LOPROC      ", "Start of processor-specific"},
	{0x7fffffff, "HIPROC      ", "End of processor-specific"},
};

I2STR p_special_section_indices[] = {
	{0,       "    UNDEF", "Undefined section"},
	{0xff00,  "LORESERVE", "Start of reserved indices"},
	{0xff00,  "   LOPROC", "Start of processor-specific"},
	{0xff00,  "   BEFORE", "Order section before all others (Solaris)."},
	{0xff01,  "    AFTER", "Order section after all others (Solaris)."},
	{0xff1f,  "   HIPROC", "End of processor-specific"},
	{0xff20,  "     LOOS", "Start of OS-specific"},
	{0xff3f,  "     HIOS", "End of OS-specific"},
	{0xfff1,  "      ABS", "Associated symbol is absolute"},
	{0xfff2,  "   COMMON", "Associated symbol is common"},
	{0xffff,  "   XINDEX", "Index is in extra table."},
	{0xffff,  "HIRESERVE", "End of reserved indices"},
};

/* Legal values for d_tag (dynamic entry type).  */
I2STR dynamic_type[] = {
	{0,  "NULL", "Marks end of dynamic section "},
	{1,  "NEEDED", "Name of needed library "},
	{2,  "PLTRELSZ", "Size in bytes of PLT relocs "},
	{3,  "PLTGOT", "Processor defined value "},
	{4,  "HASH", "Address of symbol hash table "},
	{5,  "STRTAB", "Address of string table "},
	{6,  "SYMTAB", "Address of symbol table "},
	{7,  "RELA", "Address of Rela relocs "},
	{8,  "RELASZ", "Total size of Rela relocs "},
	{9,  "RELAENT", "Size of one Rela reloc "},
	{10,  "STRSZ", "Size of string table "},
	{11,  "SYMENT", "Size of one symbol table entry "},
	{12,  "INIT", "Address of init function "},
	{13,  "FINI", "Address of termination function "},
	{14,  "SONAME", "Name of shared object "},
	{15,  "RPATH", "Library search path (deprecated) "},
	{16,  "SYMBOLIC", "Start symbol search here "},
	{17,  "REL", "Address of Rel relocs "},
	{18,  "RELSZ", "Total size of Rel relocs "},
	{19,  "RELENT", "Size of one Rel reloc "},
	{20,  "PLTREL", "Type of reloc in PLT "},
	{21,  "DEBUG", "For debugging; unspecified "},
	{22,  "TEXTREL", "Reloc might modify .text "},
	{23,  "JMPREL", "Address of PLT relocs "},
	{24,  "BIND_NOW", "Process relocations of object "},
	{25,  "INIT_ARRAY", "Array with addresses of init fct "},
	{26,  "FINI_ARRAY", "Array with addresses of fini fct "},
	{27,  "INIT_ARRAYSZ", "Size in bytes of DT_INIT_ARRAY "},
	{28,  "FINI_ARRAYSZ", "Size in bytes of DT_FINI_ARRAY "},
	{29,  "RUNPATH", "Library search path "},
	{30,  "FLAGS", "Flags for the object being loaded "},
	{32,  "ENCODING", "Start of encoded range "},
	{32,  "PREINIT_ARRAY", "Array with addresses of preinit fct"},
	{33,  "PREINIT_ARRAYSZ", "size in bytes of DT_PREINIT_ARRAY "},
	{34,  "NUM", "Number used "},
	{0x6000000d,  "LOOS", "Start of OS-specific "},
	{0x6ffff000,  "HIOS", "End of OS-specific "},
	{0x70000000,  "LOPROC", "Start of processor-specific "},
	{0x7fffffff,  "HIPROC", "End of processor-specific "},
	{DT_MIPS_NUM,  "PROCNUM", "Most used by any processor "},
/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the Dyn.d_un.d_val field of the Elf*_Dyn structure.
 * This follows Sun's approach.  */
	{0x6ffffd00,  "VALRNGLO", ""},
	{0x6ffffdf5,  "GNU_PRELINKED", "Prelinking timestamp "},
	{0x6ffffdf6,  "GNU_CONFLICTSZ", "Size of conflict section "},
	{0x6ffffdf7,  "GNU_LIBLISTSZ", "Size of library list "},
	{0x6ffffdf8,  "CHECKSUM", ""},
	{0x6ffffdf9,  "PLTPADSZ", ""},
	{0x6ffffdfa,  "MOVEENT", ""},
	{0x6ffffdfb,  "MOVESZ", ""},
	{0x6ffffdfc,  "FEATURE_1", "Feature selection (DTF_*).  "},
	{0x6ffffdfd,  "POSFLAG_1", "Flags for DT_* entries, effecting the following DT_* entry.  "},
	{0x6ffffdfe,  "SYMINSZ", "Size of syminfo table (in bytes) "},
	{0x6ffffdff,  "SYMINENT", "Entry size of syminfo "},
	{0x6ffffdff,  "VALRNGHI", ""},
//#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
//	{12,  "VALNUM", ""},

/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
 *  If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted.  */
	{0x6ffffe00,  "ADDRRNGLO", ""},
	{0x6ffffef5,  "GNU_HASH", "GNU-style hash table.  "},
	{0x6ffffef6,  "TLSDESC_PLT", ""},
	{0x6ffffef7,  "TLSDESC_GOT", ""},
	{0x6ffffef8,  "GNU_CONFLICT", "Start of conflict section "},
	{0x6ffffef9,  "GNU_LIBLIST", "Library list "},
	{0x6ffffefa,  "CONFIG", "Configuration information.  "},
	{0x6ffffefb,  "DEPAUDIT", "Dependency auditing.  "},
	{0x6ffffefc,  "AUDIT", "Object auditing.  "},
	{0x6ffffefd,  "PLTPAD", "PLT padding.  "},
	{0x6ffffefe,  "MOVETAB", "Move table.  "},
	{0x6ffffeff,  "SYMINFO", "Syminfo table.  "},
	{0x6ffffeff,  "ADDRRNGHI", ""},
//#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
//	{11,  "ADDRNUM", ""},

/* The versioning entry types.  The next are defined as part of the
   GNU extension.  */
	{0x6ffffff0,  "VERSYM", ""},

	{0x6ffffff9,  "RELACOUNT", ""},
	{0x6ffffffa,  "RELCOUNT", "These were chosen by Sun.  "},
	{0x6ffffffb,  "FLAGS_1", "State flags, see DF_1_* below.  "},
	{0x6ffffffc,  "VERDEF", "Address of version definition table "},
	{0x6ffffffd,  "VERDEFNUM", "Number of version definitions "},
	{0x6ffffffe,  "VERNEED", "Address of table with needed versions "},
	{0x6fffffff,  "VERNEEDNUM", "Number of needed versions "},
//#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
//	{16,  "VERSIONTAGNUM", "Sun added these machine-independent extensions in the "processor-specific"   range.  Be compatible.  "},
	{0x7ffffffd,  "AUXILIARY", "Shared object to load before self "},
	{0x7fffffff,  "FILTER", "Shared object to get values from "},
//#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
//	{3,  "EXTRANUM", ""},
};

I2STR aux_type[] = {
    {0, "NULL", "End of vector "},
    {1, "IGNORE", "Entry should be ignored "},
    {2, "EXECFD", "File descriptor of program "},
    {3, "PHDR", "Program headers for program "},
    {4, "PHENT", "Size of program header entry "},
    {5, "PHNUM", "Number of program headers "},
    {6, "PAGESZ", "System page size "},
    {7, "BASE", "Base address of interpreter "},
    {8, "FLAGS", "Flags "},
    {9, "ENTRY", "Entry point of program "},
    {10, "NOTELF", "Program is not ELF "},
    {11, "UID", "Real uid "},
    {12, "EUID", "Effective uid "},
    {13, "GID", "Real gid "},
    {14, "EGID", "Effective gid "},
    {17, "CLKTCK", "Frequency of times() "},

/* Some more special a_type values describing the hardware.  */
    {15, "PLATFORM", "String identifying platform.  "},
    {16, "HWCAP", "Machine dependent hints about processor capabilities.  "},

/* This entry gives some information about the FPU initialization performed by the kernel.  */
    {18, "FPUCW", "Used FPU control word.  "},

/* Cache block sizes.  */
    {19, "DCACHEBSIZE", "Data cache block size.  "},
    {20, "ICACHEBSIZE", "Instruction cache block size.  "},
    {21, "UCACHEBSIZE", "Unified cache block size.  "},

/* A special ignored value for PPC, used by the kernel to control the interpretation of the AUXV. Must be > 16.  */
    {22, "IGNOREPPC", "Entry should be ignored.  "},
    {23, "SECURE", "Boolean, was exec setuid-like?  "},
    {24, "BASE_PLATFORM", "String identifying real platforms."},
    {25, "RANDOM", "Address of 16 random bytes.  "},
    {31, "EXECFN", "Filename of executable.  "},

/* Pointer to the global system page used for system calls and other nice things.  */
    {32, "SYSINFO", ""},
    {33, "SYSINFO_EHDR", "Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains log2 of line size; mask those to get cache size."},
    {34, "L1I_CACHESHAPE", ""},
    {35, "L1D_CACHESHAPE", ""},
    {36, "L2_CACHESHAPE", ""},
    {37, "L3_CACHESHAPE", ""},
};

char* get_i2str(I2STR* arr,unsigned arr_ele_num, int i) {
	unsigned ui = 0;
	for(ui = 0; ui < arr_ele_num; ++ui) {
		if(arr[ui].i == i) {
			return arr[ui].str;
		}
	}
	return "";
}
#define GET_I2STR(arr_name, i) get_i2str(arr_name, sizeof(arr_name) / sizeof(arr_name[0]), i)

int is_in_i2str_arr(I2STR* arr,unsigned arr_ele_num, int i) {
	unsigned ui = 0;
	for(ui = 0; ui < arr_ele_num; ++ui) {
		if(arr[ui].i == i) {
			return (int)1;
		}
	}
	return 0;
}
#define IS_IN_I2STR_ARR(arr_name, i) is_in_i2str_arr(arr_name, sizeof(arr_name) / sizeof(arr_name[0]), i)

int print_proc_map() {
    pid_t pid;
    char maps[64];
    FILE *fmap;
    char c = 0;

    pid = getpid();
    printf("pid:%d\n", pid);
    sprintf(maps, "/proc/%d/maps", pid);
    fmap = fopen(maps, "rb");
    if (!fmap) {
        printf("open %s file failed!/n", maps);
        return -1;
    }

    c = fgetc(fmap);
    while (EOF != c) {
        putchar(c);
        c = fgetc(fmap);
    }
    fclose(fmap);
    return 0;
}

static char print_hex_last_char = 0xFF;
static char is_body_printing = 0;
static char st_hex_print = 0;//idle
static void sub_print_hex_with_char_16(void* buf, int buf_len, int addr_for_print, int pre_skip_cnt) {
	int i = 0;
	char* p = (char*)buf;

	if(is_body_printing && buf_len >= 16) {
	    char b_same = 1;
	    int i = 0;
	    for(i = 1; i < 16; ++i) {
	        if(p[i] != p[0]) {
	            b_same = 0;
	            break;
	        }
	    }
	    if(b_same && print_hex_last_char == p[0]) {
	        if(0 == st_hex_print) {
	            printf("*\n");
	            st_hex_print = 1;//same line ing.
	        } else if (1 == st_hex_print) {
	            //repeat, nothing to do
	        }
	        return;
	    } else {
	        st_hex_print = 0;
	        print_hex_last_char = 0xFF;
	    }
	}

	printf("%08X ", addr_for_print);
	for(i = 0; i < 16; ++i) {
		if(i < pre_skip_cnt) {
			printf("   ");
		} else if(i < buf_len + pre_skip_cnt) {
			printf("%02X ", (unsigned char)p[i - pre_skip_cnt]);
			print_hex_last_char = p[i - pre_skip_cnt];
		} else {//tail skip
			printf("   ");
		}

		if(7 == i) {
			printf(" ");
		}
	}

	printf("  ->|");
	for(i = 0; i < 16; ++i) {
		if(i < pre_skip_cnt) {
			printf(" ");
		} else if(i < buf_len + pre_skip_cnt) {
			if(isprint(p[i - pre_skip_cnt])) {
				printf("%c", p[i - pre_skip_cnt]);
			} else {
				printf("?");
			}
		} else {//tail skip
			printf(" ");
		}
		if(7 == i) {
			printf(" ");
		}
	}
	printf("|\n");
}

void print_hex_with_char(void* vbuf, int len, int bin_star_addr) {
	int i = 0;
	char* buf = vbuf;
	int all_need_print_row = 0;
	char* p_next_row_data = 0;
	int remain_len = len;
	int base_bin_star_addr = bin_star_addr & 0xFFFFFFF0;

	//columns header
	printf("         -0 -1 -2 -3 -4 -5 -6 -7  -8 -9 -A -B -C -D -E -F\n");

	//first row
	is_body_printing = 0;
	sub_print_hex_with_char_16(vbuf, len, base_bin_star_addr, bin_star_addr % 0x10);
	remain_len -= (0x10 - (bin_star_addr % 0x10));
	base_bin_star_addr += 0x10;

	//body rows
	all_need_print_row = ((bin_star_addr + len - 1) >> 4) - (bin_star_addr >> 4) + 1;
	p_next_row_data = &buf[0x10 - (bin_star_addr % 0x10)];
	while(i < all_need_print_row - 2) {
	    is_body_printing = 1;
		sub_print_hex_with_char_16(p_next_row_data, remain_len, base_bin_star_addr, 0);
		remain_len -= 0x10;
		base_bin_star_addr += 0x10;
		p_next_row_data += 0x10;
		++i;
	}
	is_body_printing = 0;

	//last row
	if(remain_len > 0) {
		sub_print_hex_with_char_16(p_next_row_data, remain_len, base_bin_star_addr, 0);
	}
}

void print_hex(void* vbuf, int len, int per_bytes, int show_decimal) {
	int i = 0;
	char* buf = vbuf;

	if(1 == per_bytes) {
		for(i = 0; i < len; ++i) {
			printf("%02X ", (unsigned char)buf[i]);
		}
	} else if(2 == per_bytes) {
		for(i = 0; i < len; i += 2) {
			unsigned short s = buf[i] | (buf[i + 1] << 8);
			if(show_decimal) {
				printf("%04X(%d) ", s, s);
			} else {
				printf("%04X ", s);
			}
		}
	} else if(4 == per_bytes) {
		for(i = 0; i < len; i += 4) {
			unsigned int ui = (buf[i]&0xFF) | 
				((buf[i + 1] << 8) & 0xFF00) | 
				((buf[i + 2] << 16) & 0xFF0000)| 
				((buf[i + 3] << 24) & 0xFF000000);
			if(show_decimal) {
				printf("%08X(%d) ", ui, ui);
			} else {
				printf("%08X ", ui);
			}
			
		}
	}
}

int read_elf_buf(char* obj_path) {
	long l = 0;

	FILE* f = fopen(obj_path, "rb");
	if(NULL == f) {
		perror("obj file open failed!\n");
		return -1;
	}

	fseek(f, 0, SEEK_END);
	l = ftell(f);

	gElfStr = (char*)malloc(l);
	fseek(f, 0, SEEK_SET);
	if(1 != fread(gElfStr, l, 1, f)){
		perror("obj file read failed!\n");
		fclose(f);
		return -1;
	}
	fclose(f);
	return 0;
}

void print_elf_header(char* obj_path) {
	Elf32_Ehdr* ph = NULL;
	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}
	ph = (Elf32_Ehdr*)gElfStr;
	
	//magic
	printf("Magic                             :");print_hex(ph->e_ident, EI_NIDENT, 1, 0);printf("\n");
	printf("Class                             :");printf("%s\n", GET_I2STR(eh_class, ph->e_ident[4]));
	printf("Data                              :");printf("%s\n", GET_I2STR(eh_data,  ph->e_ident[5]));
	printf("File Version                      :");print_hex(&ph->e_ident[6], 1, 1, 0);printf("\n");
	printf("ABI                               :");printf("%s\n", GET_I2STR(eh_abi, ph->e_ident[7]));
	printf("ABI Version                       :");print_hex(&ph->e_ident[8], 1, 1, 0);printf("\n");
	//e_type
	printf("Type                              :");printf("%s\n", GET_I2STR(eh_e_type, ph->e_type));
	printf("machine                           :");printf("%s\n", GET_I2STR(eh_e_mach, ph->e_machine));
	printf("Entry point virtual address       :");printf("%08X", ph->e_entry);printf("\n");
	printf("Program header table file offset  :");printf("%08X(%d)", ph->e_phoff, ph->e_phoff);printf("\n");
	printf("Section header table file offset  :");printf("%08X(%d)", ph->e_shoff, ph->e_shoff);printf("\n");
	printf("Processor-specific flags          :");printf("%08X", ph->e_flags);printf("\n");
	printf("ELF header size in bytes          :");printf("%04X(%d)", ph->e_ehsize, ph->e_ehsize);printf("\n");
	printf("Program header table entry size   :");printf("%04X(%d)", ph->e_phentsize, ph->e_phentsize);printf("\n");
	printf("Program header table entry count  :");printf("%04X(%d)", ph->e_phnum, ph->e_phnum);printf("\n");	
	printf("Section header table entry size   :");printf("%04X(%d)", ph->e_shentsize, ph->e_shentsize);printf("\n");
	printf("Section header table entry count  :");printf("%04X(%d)", ph->e_shnum, ph->e_shnum);printf("\n");
	printf("Section header string table index :");printf("%04X(%d)", ph->e_shstrndx, ph->e_shstrndx);printf("\n");	
}

void print_section_header(char* obj_path) {
	Elf32_Ehdr* ph = 0;
	Elf32_Shdr* psh = 0;//section header
	int i = 0;
	
	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}

	ph = (Elf32_Ehdr*)gElfStr;
	printf("header count:%d, offset of elf-file:0x%X(%d).\n", ph->e_shnum, ph->e_shoff, ph->e_shoff);
	psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);
	printf("No  Section-Name                      Type      Flag        VMA     ____Offset____  _____Size____     Link     Info    Align  EntrySize\n");
	for(i = 0; i < ph->e_shnum; ++i) {
		unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;
		printf("%02d ", i);
		if('\0' == gElfStr[name_idx]) {
			printf("NULL\n");
			continue;
		}
		printf("%18s ", &gElfStr[name_idx]);//Section name (string tbl index)
		printf("%25s ", GET_I2STR(sh_type, psh[i].sh_type));//Section type

		//Section flags
		if(SHF_WRITE & psh[i].sh_flags) {printf("W");}else{printf(" ");}
		if(SHF_ALLOC & psh[i].sh_flags) {printf("A");}else{printf(" ");}
		if(SHF_EXECINSTR & psh[i].sh_flags) {printf("E");}else{printf(" ");}
		if(SHF_MERGE & psh[i].sh_flags) {printf("M");}else{printf(" ");}//Might be merged
		if(SHF_STRINGS & psh[i].sh_flags) {printf("N");}else{printf(" ");}//Contains nul-terminated strings
		if(SHF_INFO_LINK & psh[i].sh_flags) {printf("S");}else{printf(" ");}//sh_info' contains SHT index
		if(SHF_LINK_ORDER & psh[i].sh_flags) {printf("P");}else{printf(" ");}//Preserve order after combining required
		if(SHF_OS_NONCONFORMING & psh[i].sh_flags) {printf("H");}else{printf(" ");}//Non-standard OS specific handling
		if(SHF_GROUP & psh[i].sh_flags) {printf("G");}else{printf(" ");}//Section is member of a group
		if(SHF_TLS & psh[i].sh_flags) {printf("T");}else{printf(" ");}//Section hold thread-local data.
		printf(" ");

		//sh_addr:Section virtual addr at execution
		printf("%08X ", psh[i].sh_addr);

		//sh_offset:Section file offset
		printf("%08X(%5d) ", psh[i].sh_offset, psh[i].sh_offset);

		//sh_size:Section size in bytes
		printf("%08X(%5d) ", psh[i].sh_size, psh[i].sh_size);

		//sh_link:Link to another section
		printf("%08X ", psh[i].sh_link);

		//sh_info:Additional section information
		printf("%08X ", psh[i].sh_info);

		//sh_addralign:Section alignment
		printf("%08X ", psh[i].sh_addralign);

		//sh_entsize:Entry size if section holds table
		printf("%08X ", psh[i].sh_entsize);

		printf("\n");
	}
	printf("W:Writable  A:Alloc(Occupies memory during execution)  E:Executable  M:Might be Merged  N:Contains nul-terminated strings\n");
	printf("S:sh_info' contains SHT index  P:Preserve order after combining required  H:Non-standard OS specific handling\n");
	printf("G:Section is member of a group  T:Section hold thread-local data.\n");
}

void print_section_data(char* obj_path, char* section) {
	Elf32_Ehdr* ph = 0;
	Elf32_Shdr* psh = 0;//section header
	int i = 0;

	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}
	ph = (Elf32_Ehdr*)gElfStr;

	psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);
	for(i = 0; i < ph->e_shnum; ++i) {
		unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;
		if('\0' == gElfStr[name_idx]) {
			continue;
		}

		if(0 == strcmp(section, &gElfStr[name_idx])) {
			char* p = gElfStr + psh[i].sh_offset;
			printf("VMA=%08X file_offset=%08X(%d) size=%08X(%d)\n", psh[i].sh_addr, psh[i].sh_offset, psh[i].sh_offset, psh[i].sh_size, psh[i].sh_size);
			print_hex_with_char(p, psh[i].sh_size, psh[i].sh_addr);
			return;
		}
	}
	printf("ERR:section:%s NOT FOUND\n", section);
}

//ret 0:ok -1:ng
static int sub_get_section_header(char* header_name, Elf32_Shdr* out_section_hdr) {
	Elf32_Ehdr* ph = (Elf32_Ehdr*)gElfStr;
	Elf32_Shdr* psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);//section header
	int i = 0;

	for(i = 0; i < ph->e_shnum; ++i) {
		unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;
		if(0 == strcmp(&gElfStr[name_idx], header_name)) {
			*out_section_hdr = psh[i];
			return 0;
		}

	}
	//printf("ERR:section:%s NOT FOUND\n", header_name);
	return -1;
}

static int sub_get_sym_by_idx(char* symtab_name, Elf32_Sym* psym, int idx) {
	Elf32_Shdr symtab_hdr = {0};
	Elf32_Sym* psm = 0;

	if(0 != sub_get_section_header(symtab_name, &symtab_hdr)) {
	    printf("ERR:section:%s NOT FOUND\n", ".symtab");
	    return -1;
	}

	psm = (Elf32_Sym*)&gElfStr[symtab_hdr.sh_offset];
	*psym = psm[idx];

	return 0;
}

static char* sub_section_name_by_idx(int idx) {
	Elf32_Ehdr* ph = 0;
	Elf32_Shdr* psh = 0;//section header
	int i = 0;

	ph = (Elf32_Ehdr*)gElfStr;
	psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);
	for(i = 0; i < ph->e_shnum; ++i) {
		unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;
		if(idx == i) {
			if('\0' == gElfStr[name_idx]) {
				return "NULL";
			}
			return &gElfStr[name_idx];
		}
	}
	return "NOT FOUND";
}

static void sub_print_symbol(char* sym_section_name, char* str_section_name) {
    Elf32_Shdr str_tab_hdr = {0};
    Elf32_Shdr symtab_hdr = {0};
    Elf32_Sym* psm = 0;
    int j = 0;

    if(0 != sub_get_section_header(str_section_name, &str_tab_hdr)) {
        //printf("ERR:section:%s NOT FOUND\n", ".strtab");
        return;
    }
    if(0 != sub_get_section_header(sym_section_name, &symtab_hdr)) {
        //printf("ERR:section:%s NOT FOUND\n", ".symtab");
        return;
    }

    psm = (Elf32_Sym*)&gElfStr[symtab_hdr.sh_offset];

    printf("\nSymbol table '%s' contains %d entries:\n", sym_section_name, symtab_hdr.sh_size / sizeof(Elf32_Sym));
    printf("No   Value    Size     Type   Bind  Visibility __________Ndx__________  Name\n");
    for(j = 0; j < symtab_hdr.sh_size / sizeof(Elf32_Sym); ++j) {
        char* type = NULL;
        printf("%3d ", j);//index
        printf("%08X ", psm[j].st_value); //value, uraly as addr
        printf("%08X ", psm[j].st_size); //size

        //type
        type = GET_I2STR(sym_type, ELF32_ST_TYPE(psm[j].st_info));
        printf("%s ", type);//Section type
        //bind
        printf("%s ", GET_I2STR(sym_bind, ELF32_ST_BIND(psm[j].st_info)));//Section type

        //Visibility
        printf("%s ", GET_I2STR(sym_visibility, ELF32_ST_VISIBILITY(psm[j].st_other)));//visibility

        //index

        if(IS_IN_I2STR_ARR(p_special_section_indices, psm[j].st_shndx)) {
            printf("%04X(%18s) ", psm[j].st_shndx, GET_I2STR(p_special_section_indices, psm[j].st_shndx));//special index
        } else {
            printf("%04X(%18s) ", psm[j].st_shndx, sub_section_name_by_idx(psm[j].st_shndx)); //Section index
        }

        //symbol name
        printf("%s ", &gElfStr[str_tab_hdr.sh_offset + psm[j].st_name]);

        printf("\n");
    }
}

void print_symbol(char* obj_path) {
	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}
	sub_print_symbol(".dynsym", ".dynstr");
	sub_print_symbol(".symtab", ".strtab");

	printf("----------------------------------------\n");
	printf("BIND  LOCAL: 局部符号,对于目标文件外部不可见 GLOBAL:全局符号,外部可见 WEEK:弱引用\n");
	printf("TYPE  NOTYPE:未知 OBJECT:数据对象,如变量/数组 FUNC:函数或其它可执行代码 SECTION:段,必为LOCAL FILE:文件名\n");
	printf("Ndx   符号所在段的下标,注意特殊段\n");
	printf("----------------------------------------\n");
}

static void sub_print_relocation_info(Elf32_Shdr* rel_hdr, char* rel_scetion_name, Elf32_Shdr* str_hdr) {
    Elf32_Rel* pr = 0;
    int i = 0;
    int entry_cnt = 0;

    pr = (Elf32_Rel*)(gElfStr + rel_hdr->sh_offset);
    entry_cnt = rel_hdr->sh_size / sizeof(Elf32_Rel);
    printf("\nRelocation section '%s' at offset 0x%x contains %d entries:\n", rel_scetion_name, rel_hdr->sh_offset, entry_cnt);
    printf("No.   offset   info   TYPE.name           sym.Value sym.Name\n");
    for(i = 0; i < entry_cnt; ++i, pr++) {
        Elf32_Sym sym;
        if(0 == strcmp(rel_scetion_name, ".rel.dyn") || 0 == strcmp(rel_scetion_name, ".rel.plt")) {
            Elf32_Shdr share_obj_str_tab = {0};
            sub_get_sym_by_idx(".dynsym", &sym, ELF32_R_SYM(pr->r_info));
            if(0 != sub_get_section_header(".dynstr", &share_obj_str_tab)) {
                printf("ERR:section:%s NOT FOUND\n", ".dynsym");
                continue;
            }
            str_hdr = &share_obj_str_tab;
        } else {
            sub_get_sym_by_idx(".symtab", &sym, ELF32_R_SYM(pr->r_info));
        }

        printf("%03d %08X %08X ", i, pr->r_offset, pr->r_info);

        //type
        if(0 == strcmp("ELFCLASS32", GET_I2STR(eh_class, gElfStr[4]))) {
            printf("%s ", GET_I2STR(reloc_type_i386, ELF32_R_TYPE(pr->r_info)));
        } else {
            printf("non-i386 TODO      ");
        }


        //sym value
        printf("%08X ", sym.st_value);

        //sym name
        printf(" %s\n", &gElfStr[str_hdr->sh_offset + sym.st_name]);
    }
}

void print_relocation_info(char* obj_path) {
	Elf32_Shdr str_hdr = {0};
    Elf32_Ehdr* ph = NULL;
    Elf32_Shdr* psh = NULL;//section header
    int i = 0;

	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}
    ph = (Elf32_Ehdr*)gElfStr;
    psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);//section header

    if(0 != sub_get_section_header(".strtab", &str_hdr)) {
        //shared-object maybe no .strtab
    }

    for(i = 1; i < ph->e_shnum; ++i) {//skip 1st empty-item
        unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;//Section name (string tbl index)
        if(0 == memcmp(&gElfStr[name_idx], ".rel.", strlen(".rel."))) {
            sub_print_relocation_info(&psh[i], &gElfStr[name_idx], &str_hdr);
        }
    }
}

static void sub_get_section_segment_mapping(int segment_load_start, int segment_load_end) {
	Elf32_Ehdr* ph = 0;
	Elf32_Shdr* psh = 0;//section header
	int i = 0;

	ph = (Elf32_Ehdr*)gElfStr;
	psh = (Elf32_Shdr*)(gElfStr + ph->e_shoff);
	for(i = 1; i < ph->e_shnum; ++i) {//start at 1, skip the empty section
		unsigned int name_idx = psh[ph->e_shstrndx].sh_offset + psh[i].sh_name;
		int section_virtual_addr_start = psh[i].sh_addr;
		int section_virtual_addr_end = psh[i].sh_addr + psh[i].sh_size - 1;
		//printf("    sec[%x, %x]\n", section_virtual_addr_start, section_virtual_addr_end);
		if((section_virtual_addr_start >= segment_load_start) &&
				(section_virtual_addr_end <= segment_load_end) &&
				(section_virtual_addr_start != 0)) {
			printf("%s ", &gElfStr[name_idx]);//Section name (string tbl index)
		}

	}
}
void print_programe_header_info(char* obj_path) {
	Elf32_Ehdr* ph = 0;
	Elf32_Phdr* pphr = 0;
	int i = 0;


	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}

	ph = (Elf32_Ehdr*)gElfStr;
	pphr = (Elf32_Phdr*)(gElfStr + ph->e_phoff);

	printf("Elf file Type is %s, ", GET_I2STR(eh_e_type, ph->e_type));
	printf("Entry point virtual address@0x%X(%d)\n", ph->e_entry, ph->e_entry);
	printf("programe header count:%d, offset@0x%X(%d)\n", ph->e_phnum, ph->e_phoff, ph->e_phoff);

	printf("No. Type         Offset   VirAddr  PhyAddr  FileSize MemSize  Flags Align\n");
	for(i = 0; i <  ph->e_phnum; ++i, pphr++) {
		char* type_str = GET_I2STR(p_type_info, pphr->p_type);
		//No.
		printf("%03d ", i);

		//Type
		printf("%s ", type_str);

		//offset
		printf("%08X ", pphr->p_offset);

		//virtual address, physical address
		printf("%08X %08X ", pphr->p_vaddr, pphr->p_paddr);

		//file size, mem size
		printf("%08X %08X ", pphr->p_filesz, pphr->p_memsz);

		//flags
		if(pphr->p_flags & PF_X) {printf("X");} else {printf(" ");}
		if(pphr->p_flags & PF_W) {printf("W");} else {printf(" ");}
		if(pphr->p_flags & PF_R) {printf("R");} else {printf(" ");}
		if(pphr->p_flags & PF_MASKOS) {printf("O");} else {printf(" ");}
		if(pphr->p_flags & PF_MASKPROC) {printf("P");} else {printf(" ");}

		//align
		printf(" %08X ", pphr->p_align);

		//output the interpreter
		if(0 == memcmp("INTERP", type_str, strlen("INTERP"))) {
			char* interpreter = &gElfStr[pphr->p_offset];
			printf(" ->%s", interpreter);
		}

		printf("\n");
	}

	//section to segment mapping
	printf("\nSection to Segment mapping:\n");
	pphr = (Elf32_Phdr*)(gElfStr + ph->e_phoff);//reset programe header pointer.
	for(i = 0; i <  ph->e_phnum; ++i, pphr++) {
		//No.
		printf("%03d ", i);

		//get mapping
		//printf("seg[%x, %x]\n", pphr->p_vaddr, pphr->p_vaddr + pphr->p_memsz - 1);
		sub_get_section_segment_mapping(pphr->p_vaddr, pphr->p_vaddr + pphr->p_memsz - 1);
		printf("\n");
	}
}

void print_dynamic_info(char* obj_path) {
	Elf32_Shdr dynamic_hdr = {0};
	Elf32_Dyn* p_dyn_item = NULL;
	int i = 0;
	int entry_cnt = 0;

	if(NULL == gElfStr) {
		read_elf_buf(obj_path);
	}

    if (0 != sub_get_section_header(".dynamic", &dynamic_hdr)) {
        printf("ERR:section:%s NOT FOUND\n", ".dynamic");
        return;
    }
	p_dyn_item = (Elf32_Dyn*)(gElfStr + dynamic_hdr.sh_offset);

	entry_cnt = dynamic_hdr.sh_size / sizeof(Elf32_Dyn);
	printf("Dynamic section at offset 0x%X contains %d entries:\n", dynamic_hdr.sh_offset, entry_cnt);
	printf("No. ________Tag___________ _____Type_____ Name/Value\n");
	for(i = 0; i <  entry_cnt; ++i, p_dyn_item++) {
		printf("%03d %08X(%12d) %14s %08X(%d)", i, p_dyn_item->d_tag, p_dyn_item->d_tag, GET_I2STR(dynamic_type, p_dyn_item->d_tag), p_dyn_item->d_un.d_ptr, p_dyn_item->d_un.d_ptr);
		if(1 == p_dyn_item->d_tag) { //NEEDED, get the dependent lib name
			Elf32_Shdr dynamic_str_hdr = {0};
			if(0 != sub_get_section_header(".dynstr", &dynamic_str_hdr)) {
			    printf("ERR:section:%s NOT FOUND\n", ".dynstr");
			    continue;
			}
			printf(" ->%s", gElfStr + dynamic_str_hdr.sh_offset + p_dyn_item->d_un.d_val);
		}
		printf("\n");
	}
}

void print_aux_info(char** argv, void* argv_addr) {
    int i = 0;
    unsigned int dump_addr_max = 0;
    unsigned int argv_4 = 0;
    unsigned int addr, str_start, str_end, str_len;
    unsigned int it = 0;
    Elf32_auxv_t* aux = NULL;
    int argc = 0;//main's argc
    int envc = 0;//env item count
    int auxc = 0;//aux item count

    //argc = *(int*)(VA(cur_ebp) + 8);
    argv_4 = VA(argv - 1);
    argc = *(int*)argv_4;
    printf("----------------Argments--------------------\n");
    printf("[%08X] argc:%d\n", (unsigned int)(argv - 1), argc);
    for(; i < argc; ++i) {
        str_len = strlen(argv[i]);
        addr = VA(&argv[i]);
        str_start = VA(argv[i]);
        str_end = VA(argv[i] + str_len);

        if(str_end > dump_addr_max) {
            dump_addr_max = str_end;
        }
        printf("[%08X][%08X-%08X][%02d] argv[%d]:%s\n", addr, str_start, str_end, str_len, i, argv[i]);
    }
    printf("----------------Environment Var--------------------\n");
    ++i;//skip the emptye item

    //env string
    while(argv[i]) {
        str_len = strlen(argv[i]);
        addr = VA(&argv[i]);
        str_start = VA(argv[i]);
        str_end = VA(argv[i] + str_len);

        if(str_end > dump_addr_max) {
            dump_addr_max = str_end;
        }

        printf("[%08X][%08X-%08X][%02d] env[%d]:%s\n", addr, str_start, str_end, str_len, i - argc - 1, argv[i]);
        ++envc;
        ++i;
    }
    printf("----------------Auxiliary vector--------------------\n");
    ++i;//skip the emptye item

    aux = (Elf32_auxv_t*)&argv[i];
    printf("                                         aux_type    value\n");
    while(aux->a_type != AT_NULL) {
        printf("[%08X][%08X-%08X][%02d][%02d] %15s 0x%08X(%d)\n", (unsigned int)aux, (unsigned int)aux,
                (unsigned int)((char*)aux + sizeof(Elf32_auxv_t) - 4), sizeof(Elf32_auxv_t), auxc,
                GET_I2STR(aux_type, aux->a_type), aux->a_un.a_val, aux->a_un.a_val);
        ++auxc;
        ++aux;
    }
    if((unsigned int)aux > (unsigned int)dump_addr_max) {//useless usualy
        dump_addr_max = VA(aux);
    }

    printf("----------------Mem Dump [main's ebp, &aux[max]], human-readable --------------------\n");
    {//print aux
        int j = 0;
        //aux = (Elf32_auxv_t*)(VA(argv) + (argc + 1) * 4 + (envc + 1) * 4 + auxc * sizeof(Elf32_auxv_t));//re-calc, yet no problem
        //aux pointer use last dump result is ok, use
        it = (unsigned int)aux;
        printf("      %08X %08X\n", it + 4, *(int*)(it + 4));
        printf("      %08X %08X(aux[end])\n", it, *(int*)it);
        it -= sizeof(Elf32_auxv_t);//8

        for(j = auxc - 1; j >= 0; --j) {
            printf("      %08X %08X\n", it + 4, *(int*)(it + 4));
            printf("      %08X %08X(aux[%d])\n", it, *(int*)it, j);
            it -= sizeof(Elf32_auxv_t);//8
        }
        it += sizeof(Elf32_auxv_t);//roll back
        it -= sizeof(char*);//re-loc
    }
    {//print env
        int j = 0;

        printf("      %08X %08X(env[end])\n", it, *(int*)it);
        it -= sizeof(char*);

        for(j = envc - 1; j >= 0; --j) {
            printf("      %08X %08X(env[%d]->%s)\n", it, *(int*)it, j, (char*)(*(int*)it));
            it -= sizeof(char*);
        }
    }
    {//print argv
        int j = 0;

        printf("      %08X %08X(argv[end])\n", it, *(int*)it);
        it -= sizeof(char*);

        for(j = argc - 1; j >= 0; --j) {
            if(0 == j) {
                printf("argv->");
            } else {
                printf("      ");
            }
            printf("%08X %08X(argv[%d]->%s)\n", it, *(int*)it, j, (char*)(*(int*)it));
            it -= sizeof(char*);
        }
    }
    printf("----[ENTRY] _start run\n");
    while(it & 0xF) {
        printf("      %08X %08X(for align-16, invalid)\n", it, *(int*)it);
        it -= sizeof(char*);
    }
    printf("      %08X %08X(for align-16, maybe the argc, invalid(see popl %%esi     /* Pop the argument count.  */))\n", it, *(int*)it);it -= sizeof(char*);

    printf("      %08X %08X(kernerl transimited eax(garbage). see glibc-2.23\\sysdeps\\i386\\start.S:74) <-|\n", it, *(int*)it);it -= sizeof(char*);
    printf("      %08X %08X(main_param[6] stack_end) ---------------------------------------------------|\n", it, *(int*)it);it -= sizeof(char*);
    printf("      %08X %08X(main_param[5] rtld_fini)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X(main_param[4] fini)\n", it, *(int*)it);it -= sizeof(char*);
    printf("      %08X %08X(main_param[3] init)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X(main_param[2] ubp_av, alias argv)\n", it, *(int*)it);it -= sizeof(char*);
    printf("      %08X %08X(main_param[1] argc)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X(main_param[0] main func addr)\n", it, *(int*)it); it -= sizeof(char*);
    printf("------call __libc_start_main\n");
    printf("      %08X %08X(lr after __libc_start_main)\n", it, *(int*)it);it -= sizeof(char*);

    while(it > (VA(argv_addr) + 1 * 4)) {
        printf("      %08X %08X\n", it, *(int*)it);
        it -= sizeof(char*);
    }

    printf("      %08X %08X(envv, implicit transmission to main)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X(argv)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X(argc)\n", it, *(int*)it); it -= sizeof(char*);
    printf("------call main\n");
    printf("      %08X %08X(lr)\n", it, *(int*)it); it -= sizeof(char*);
    printf("      %08X %08X\n", it, *(int*)it); it -= sizeof(char*);
    while(it > (VA(cur_ebp))) {
        printf("      %08X %08X\n", it, *(int*)it);
        it -= sizeof(char*);
    }
    printf("main's ebp->%08X %08X\n", (int)cur_ebp, *(int*)it);

    printf("----------------Mem Dump(RAW)--------------------\n");
    print_hex_with_char((void*)argv_4, dump_addr_max - argv_4, argv_4);
    printf("----------------Proc Maps--------------------\n");
    print_proc_map();
    printf("----------------End--------------------\n");
}

void print_help() {
	printf("myreadelf -h Display the ELF file header\n");
	printf("myreadelf -S Display the sections' header\n");
	printf("myreadelf -s Display the symbol table\n");
	printf("myreadelf -o`section_name` elffile:show Section's data.\n          sample:myreadelf -o.text myreadelf\n");
	printf("myreadelf -r Display the relocations (if present).\n");
	printf("myreadelf -l Display the program headers.\n");
	printf("myreadelf -d Display the dynamic section (if present).\n");
	printf("myreadelf -x Display Auxiliary vector and params...\n");
}

int main(int argc, char* argv[]) {
	if(2 == argc && 0 == strcmp("--help", argv[1])) {
		print_help();
	} else if(3 == argc && 0 == strcmp("-h", argv[1])) {
		print_elf_header(argv[2]);
	} else if(3 == argc && 0 == strcmp("-S", argv[1])) {
		print_section_header(argv[2]);
	} else if(3 == argc && 0 == strcmp("-s", argv[1])) {
		print_symbol(argv[2]);
	} else if(3 == argc && 0 == memcmp("-o", argv[1], 2)) {
		print_section_data(argv[2], &argv[1][2]);
	} else if(3 == argc && 0 == strcmp("-r", argv[1])) {
		print_relocation_info(argv[2]);
	} else if(3 == argc && 0 == strcmp("-l", argv[1])) {
		print_programe_header_info(argv[2]);
	} else if(3 == argc && 0 == strcmp("-d", argv[1])) {
        print_dynamic_info(argv[2]);
    } else if(2 <= argc && 0 == strcmp("-x", argv[1])) {
        __asm__ __volatile__("mov %%ebp, %0":"=r"(cur_ebp));
        printf("main's ebp=0x%x\n", (int)cur_ebp);
        print_aux_info(argv, &argv);
    } else {
		perror("param error\n");
		return -1;
	}
	free(gElfStr);
	gElfStr = NULL;
	return 0;
}


